//
// Created by fangp on 3/10/18.
//

#include "launcher.h"

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <values.h>
#include "common.h"
#include "../config/sys.h"
#include "loaderengine.h"
#include "../init/oop.h"
#include "../trans/parser.h"
#include "fpengine.h"

#define SYS_MACRO_FILE   "engine/config/sys.macro"
#define OOP_GEN_FILE     "engine/config/oop.gen"
#define INIT_FILE        "engine/init/init.fn"

Funny *alloc_funny() {
    return (Funny *) sys_malloc(sizeof(Funny));
}

void start_translate() {
    String basePath;
    int result = hashmap_get(globalFunny->componentPaths, globalFunny->component, (void **) (&basePath));
    if (result == MAP_MISSING) {
        fprintf(stderr, "Cannot find component: %s\n", globalFunny->component);
        exit(EXIT_FAILURE);
    }
    String componentPath = append_path(basePath, globalFunny->component);
    String componentFilePath = append_path(componentPath, COMPONENT_FILE);
    read_file(componentFilePath, explain);
    construct_graph();
    Queue *queue = topological_sort(globalFunny->components);
    build_meta_data(queue);
    generate_code();
}

void parse_global_config() {
    String sysMacroFile = append_path(globalFunny->homeDir, SYS_MACRO_FILE);
    String oopGenFile = append_path(globalFunny->homeDir, OOP_GEN_FILE);
    String initFile = append_path(globalFunny->homeDir, INIT_FILE);

    chdir(globalFunny->homeDir);
    read_file(sysMacroFile, parse_sys_macro);
    chdir(globalFunny->homeDir);
    read_file(oopGenFile, parse_oop_gen);
    chdir(globalFunny->homeDir);
    read_file(initFile, explain);
    chdir(globalFunny->cwd);
}


int funny_init(LaunchArgs *args) {
    Funny *funny = alloc_funny();
    char currentPath[PATH_MAX];
    if (getcwd(currentPath, sizeof(currentPath)) == NULL) {
        perror("getcwd() error");
        return FALSE;
    }
    funny->cwd = currentPath;

    char *funnyHome = getenv(FUNNY_HOME);
    if (funnyHome == NULL) {
        fprintf(stderr, "You should set the environment variable 'FUNNY_HOME' first!");
        exit(EXIT_FAILURE);
    }
    funny->homeDir = funnyHome;
    funny->component = args->component;
    funny->repositories = args->repositories;

    funny->repoPaths = split_strings(funny->repositories, ",");
    funny->componentPaths = hashmap_new();

    funny->rules = hashmap_new();
    funny->lexOrders = NULL;

    funny->macros = hashmap_new();
    init_macro_functions(funny);
    funny->oopCodes = hashmap_new();

    funny->components = init_graph();
    funny->modules = init_queue();
    funny->functions = init_queue();
    funny->dependencies = init_queue();
    funny->executables = init_queue();
    funny->mappingTrie = init_trie(calc_mapping_prefix, calc_statement_prefix);
    funny->inheritance = init_tree();

    globalFunny = funny;
    parser = parse;
    matcher = match;
    return TRUE;
}

void launch(LaunchArgs *args) {
    if (!funny_init(args)) {
        fprintf(stderr, "Initialize funny environment error!\n");
        exit(EXIT_FAILURE);
    }
    cache_component_path(globalFunny->component);
    parse_global_config();
    start_translate();
}
